package com.dh.core.auth.filter;

import java.io.IOException;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;

import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.util.CollectionUtils;
import org.springframework.web.filter.OncePerRequestFilter;

import com.dh.core.auth.config.JwtProperties;
import com.dh.core.auth.dto.SimpleAuthorizationInfo;
import com.dh.core.auth.tip.ErrorTip;
import com.dh.core.auth.utils.JwtTokenUtil;
import com.dh.core.auth.utils.RenderUtil;
import com.dh.core.auth.utils.TokenManagementUtil;
import com.dh.core.common.enums.BizExceptionEnum;
import com.dh.entity.Permission;
import com.dh.entity.Role;
import com.dh.entity.User;
import com.dh.service.RolePermissionService;
import com.dh.service.UserRoleService;
import com.dh.service.UserService;

import io.jsonwebtoken.JwtException;

/**
 * 
 * @ClassName: AuthFilter
 * @Description: 对客户端请求的jwt token验证过滤器
 * @author dinghao
 * @date 2018年12月4日 上午10:01:02
 *
 */
public class AuthFilter extends OncePerRequestFilter {

	@Autowired
	private JwtTokenUtil jwtTokenUtil;

	@Autowired
	private JwtProperties jwtProperties;

	@Autowired
	private UserService userService;

	@Autowired
	private UserRoleService userRoleService;

	@Autowired
	private RolePermissionService rolePermissionService;

	@Override
	protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain)
			throws IOException, ServletException {
		// 判断是否为认证请求的路径
		if (request.getServletPath().equals("/" + jwtProperties.getAuthPath())
				|| StringUtils.containsAny(request.getServletPath(), "swagger", "webjars", "swagger-resources", "error",
						"v2/api-docs", "jwtParamesEncrypt","/logout")) {
			chain.doFilter(request, response);
			return;
		}
		// 获取请求头
		final String requestHeader = request.getHeader(jwtProperties.getHeader());
		String authToken = null;
		// 请求头携带的jwt,必须以Bearer开头
		if (requestHeader != null && requestHeader.startsWith("Bearer ")) {
			authToken = requestHeader.substring(7);
			try {
				// 验证token是否过期
				boolean flag = jwtTokenUtil.isTokenExpired(authToken);
				if (flag) {
					RenderUtil.renderJson(response, new ErrorTip(BizExceptionEnum.TOKEN_EXPIRED.getCode(),
							BizExceptionEnum.TOKEN_EXPIRED.getMessage()));
					return;
				}
			} catch (JwtException e) {
				// 有异常就是token解析失败
				RenderUtil.renderJson(response, new ErrorTip(BizExceptionEnum.TOKEN_ERROR.getCode(),
						BizExceptionEnum.TOKEN_ERROR.getMessage()));
				return;
			}
		} else {
			// 用户没有登录
			if (requestHeader == null) {
				RenderUtil.renderJson(response, new ErrorTip(BizExceptionEnum.USER_NO_LOGIN.getCode(),
						BizExceptionEnum.USER_NO_LOGIN.getMessage()));
				return;
			}
			// header没有带Bearer字段
			RenderUtil.renderJson(response,
					new ErrorTip(BizExceptionEnum.TOKEN_ERROR.getCode(), BizExceptionEnum.TOKEN_ERROR.getMessage()));
			return;
		}

		/**
		 * 系统内部管理token tokenManagementUtil 1. 登入时添加进去 2. 登出时删除 解决jwt无法退出而使jwt失效的问题
		 */
		if (!TokenManagementUtil.tokenIsExist(authToken)) {
			// 该用户已经退出登录,请重新登录
			RenderUtil.renderJson(response,
					new ErrorTip(BizExceptionEnum.USER_LOGOUT.getCode(), BizExceptionEnum.USER_LOGOUT.getMessage()));
			return;
		}

		/**
		 * 通过token获取username,根据username获取权限
		 */
		// info存储用户角色权限信息
		SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
		// 获取用户名
		String usernameFromToken = jwtTokenUtil.getUsernameFromToken(authToken);
		// 通过用户获取用户信息
		User user = userService.findByUsername(usernameFromToken);
		// 通过用户id获取角色列表
		List<Role> roleList = userRoleService.findByUid(user.getUid());
		// 创建权限列表
		List<Permission> permissionList = new ArrayList<>();
		// 判断角色列表不为空
		if (!CollectionUtils.isEmpty(roleList)) {
			List<String> roles = roleList.stream().map(Role::getName).collect(Collectors.toList());
			info.addRoles(roles);
			Set<String> permissions = new HashSet<>();
			for (Role role : roleList) {
				permissionList = rolePermissionService.findByRid(role.getRid());
				if (!CollectionUtils.isEmpty(permissionList)) {
					permissions = permissionList.stream().map(Permission::getUrl).collect(Collectors.toSet());
					info.addStringPermissions(permissions);
				}
			}
			// 角色列表为空
		} else {
			// 该用户没有角色
			RenderUtil.renderJson(response,
					new ErrorTip(BizExceptionEnum.NO_ROLE.getCode(), BizExceptionEnum.NO_ROLE.getMessage()));
			return;
		}
		// 请求路径("/hello/lala")
		String servletPath = request.getServletPath();
		if (info.getStringPermissions().contains(servletPath) || info.getStringPermissions().contains("/*")) {
			chain.doFilter(request, response);
		} else {
			// 该用户没有权限
			RenderUtil.renderJson(response, new ErrorTip(BizExceptionEnum.NO_PERMISSION.getCode(),
					BizExceptionEnum.NO_PERMISSION.getMessage()));
			return;
		}
	}
}